#include <stm32l1xx.h>
#include <usart.h>
#include <inttypes.h>
#include <flash.h>
//#include <stdlib.h>

#define USART_TX_BUF_EXP 4
#define USART_TX_BUF_SIZE (1 << USART_TX_BUF_EXP)
#define USART_TX_BUF_MASK (USART_TX_BUF_SIZE - 1)

#define USART_RX_BUF_EXP 5
#define USART_RX_BUF_SIZE (1 << USART_RX_BUF_EXP)
#define USART_RX_BUF_MASK (USART_RX_BUF_SIZE - 1)

#define USART1_DMA_DONE (READ_BIT(DMA1 -> ISR,DMA_ISR_TCIF4))
#define USART1_DMA_ENABLED (READ_BIT(DMA1_Channel4 -> CCR,DMA_CCR4_EN))

USART_DMA_DESCRIPTOR
	usart_tx_xfer[USART_TX_BUF_SIZE] = {
		{.payload.address = 0,.length = 0}
	};

uint8_t usart_rx_xfer[USART_RX_BUF_SIZE];

uint8_t usart_tx_xfernum = 0;
uint8_t usart_tx_xfer_first = 0;
uint8_t usart_tx_xfer_last = 0;                         
uint8_t usart_rx_xfernum = 0;
uint8_t usart_rx_xfer_first = 0;
uint8_t usart_rx_xfer_last = 0;                         
//#define isRX (usart_rx_xfernum)


inline void startUSARTDMA(void) {
	CLEAR_BIT(DMA1_Channel4 -> CCR,DMA_CCR4_EN); // disable DMA
	DMA1_Channel4 -> CPAR = (int) &(USART1 -> DR); // prenasaj UART data register
/*
	if (usart_tx_xfer[usart_tx_xfer_first].length == 0) {
		DMA1_Channel4 -> CNDTR = 1;
		DMA1_Channel4 -> CMAR  = &usart_tx_xfer[usart_tx_xfer_first].payload.character;//&USART_TX_DMA_CHAR;
	}
	else {
		DMA1_Channel4 -> CNDTR = usart_tx_xfer[usart_tx_xfer_first].length;
		DMA1_Channel4 -> CMAR  = usart_tx_xfer[usart_tx_xfer_first].payload.address;
	}
*/
	DMA1_Channel4 -> CNDTR = (usart_tx_xfer[usart_tx_xfer_first].length) ? usart_tx_xfer[usart_tx_xfer_first].length : 1;
	DMA1_Channel4 -> CMAR  = &usart_tx_xfer[usart_tx_xfer_first].message;


	DMA1_Channel4 -> CCR |= DMA_CCR4_MINC | DMA_CCR4_DIR | DMA_CCR4_TCIE;   // from memory to peripheral, trasfer complete interrupt 
										// enable
	usart_tx_xfer_first++;
	usart_tx_xfer_first &= USART_TX_BUF_MASK;
	SET_BIT(DMA1_Channel4 -> CCR,DMA_CCR4_EN); // DMA xfer start
}

void DMA1_Channel4_IRQHandler(void) {
	usart_tx_xfernum--;
	CLEAR_BIT(DMA1_Channel4 -> CCR,DMA_CCR4_EN); // disable DMA
	SET_BIT(DMA1 -> IFCR,DMA_IFCR_CGIF4); // global interrupt flag clear

	if (usart_tx_xfernum != 0)
		startUSARTDMA();
}

void USART1_DMAputc(uint8_t ch) {
	while (usart_tx_xfernum > (USART_TX_BUF_SIZE - 1)) ; // cakaj na volne miesto v buffri
	usart_tx_xfer[usart_tx_xfer_last].length = 0;
//	usart_tx_xfer[usart_tx_xfer_last].payload.character = ch;
	usart_tx_xfer[usart_tx_xfer_last].message[0] = ch;
	usart_tx_xfer_last++;
	usart_tx_xfer_last &= USART_TX_BUF_MASK; // posunutie ukazatela na prvu volnu polozku
	usart_tx_xfernum++; // zvysenie pocitadla prenosov
	if (!USART1_DMA_ENABLED) {
		startUSARTDMA();
	}
}

void USART1_DMAsend(char *msg,uint32_t len) { // iba spravy v pevnej pamati !!!
	uint8_t i;

	while (usart_tx_xfernum > (USART_TX_BUF_SIZE - 1)) ; // cakaj na volne miesto v buffri
	usart_tx_xfer[usart_tx_xfer_last].length = len; // nastav dlzku spravy
//	usart_tx_xfer[usart_tx_xfer_last].payload.address = (uint32_t) msg; // adresa spravy
	for (i = 0;i<len;i++)
		usart_tx_xfer[usart_tx_xfer_last].message[i] = msg[i];

	usart_tx_xfer_last++;
	usart_tx_xfer_last &= USART_TX_BUF_MASK; // posunutie ukazatela na prvu volnu polozku
	usart_tx_xfernum++; // zvysenie pocitadla prenosov
	if (!USART1_DMA_ENABLED) {
		startUSARTDMA();
	}
}

void USART1_IRQHandler(void) {
	uint8_t temp;

	if (READ_BIT(USART1 -> SR,USART_SR_RXNE)) {
		temp = USART1 -> DR;
		usart_rx_xfer[usart_rx_xfer_last] = temp;
//		USART1 -> DR = temp;
		usart_rx_xfer_last = (usart_rx_xfer_last + 1) & USART_RX_BUF_MASK;
		usart_rx_xfernum++;
	}
}

uint8_t getChar(void) { //blocking
	uint8_t temp;
	
	while (!usart_rx_xfernum) ;
	
	temp = usart_rx_xfer[usart_rx_xfer_first];
	usart_rx_xfer_first = (usart_rx_xfer_first + 1) & USART_RX_BUF_MASK;
	usart_rx_xfernum--;

	return temp;
}

void usart_init(void) {
	//USART1 -> BRR = (6 << 4) + 13;   //  4194 kHz/(38400*8*2)  =  6.82617     6+13/16
	//USART1 -> BRR = (26 << 4) + 1;   // 16000 kHz/(38400*8*2)  = 26.042      26+ 1/16
	//USART1 -> BRR = (17 << 4) + 6;   // 16000 kHz/(57600*8*2)  = 17.361      17+ 6/16
	USART1 -> BRR = (8 << 4) + 11;     // 16000 kHz/(115200*8*2) =  8.6806      8+11/16
	CLEAR_BIT(USART1 -> CR1,USART_CR1_TE);	
	USART1 -> CR1 |= USART_CR1_UE | USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE; // Enable UART, transmitter and receiver
	CLEAR_BIT(DMA1_Channel4 -> CCR,DMA_CCR4_EN); // disable DMA
	USART1 -> CR3 |= USART_CR3_DMAT; // DMA pre vysielanie
	
	usart_tx_xfernum = 0;
	usart_tx_xfer_first = 0;
	usart_tx_xfer_last = 0;
	usart_rx_xfernum = 0;
	usart_rx_xfer_first = 0;
	usart_rx_xfer_last = 0;

	NVIC_EnableIRQ(USART1_IRQn); // povolit prerusenie
	NVIC_EnableIRQ(DMA1_Channel4_IRQn); // povolit prerusenie
}

void USART1_sendINT(int32_t temp,uint8_t len) {
	uint8_t send[11] = "          ";
	uint8_t i;
	
	if (len > 9)
		len = 9;
	send[0] = temp > 0 ? '+' : '-';
	temp = temp > 0 ? temp : -temp;
	for(i = len; temp && (i-1) ; --i, temp /= 10)
		send[i] = "0123456789"[temp % 10];
//	for (;i-1;i--)
//		send[i] = ' ';
	USART1_DMAsend(send,len+1);
}

